#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <execinfo.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>
#include <stdarg.h>

#define REASONABLE_TIME 5
#define REASONABLE_VOLUNTARY_SWITCH 10
#define REASONABLE_NONVOLUNTARY_SWITCH 10

jmp_buf env;

void ShowStack()
{
    int tem_cpsr = 0;
    printf("show stack\n");
    int i;
    void *buffer[1024];
    int n = backtrace(buffer, 1024);
    printf("%d\n", n);
    char **symbols = backtrace_symbols(buffer, n);
    for (i = 0; i < n; i++)
    {
        printf("%s\n", symbols[i]);
    }


    return;
}

int check_voluntary_ctxt_switches()
{
    pid_t pid = getpid();
    char proc_status_file_name[30];
    sprintf(proc_status_file_name, "/proc/%d/status", pid);
    printf("%s\n", proc_status_file_name);
    FILE *fp = fopen(proc_status_file_name, "r");
    char name[1024];
    char num[1024];
    int voluntary, nonvoluntary;
    while (1)
    {
        fscanf(fp, "%s\t%s", num, name);
        if (feof(fp))
        {
            break;
        }
        if (!strcmp("voluntary_ctxt_switches:", name))
        {
            printf("get voluntary switches : %s\n", num);
            voluntary = atoi(num);
        }
        if (!strcmp("nonvoluntary_ctxt_switches:", name))
        {
            printf("get nonvoluntary switches : %s\n", num);
            nonvoluntary = atoi(num);
        }
    }
    fclose(fp);

    if (1) // set "error" status
    {
        return 0;
    }
    else
    {
        return 1;
    }
}

void SigSegvProc(int signo)
{
    if (signo == SIGSEGV)
    {
        printf("Receive SIGSEGV signal\n");
    }
    else if (signo == SIGBUS)
    {
        printf("Receive SIGBUS signal\n");
    }
    else if (signo == SIGILL)
    {
        printf("Receive SIGSEGV signal\n");
    }
    else if (signo == SIGALRM)
    {
        printf("Receive SIGALRM signal\n");
        if (check_voluntary_ctxt_switches())
        {
            alarm(REASONABLE_TIME);
            return;
        }
    }
    else
    {
        printf("this is sig %d", signo);
    }
    ShowStack();
    siglongjmp(env, 1);
}

void RegSig()
{
    signal(SIGSEGV, SigSegvProc);
    signal(SIGBUS, SigSegvProc);
    signal(SIGILL, SigSegvProc);
    signal(SIGALRM, SigSegvProc);
    alarm(REASONABLE_TIME);
}

void func6()
{
    raise(SIGILL);
}

void func5()
{
    func6();
}

void func4()
{
    raise(SIGBUS);
}

void func3()
{
    func4();
}

void func2()
{
    raise(SIGSEGV);
}

void func1()
{
    func2();
}

int main(int argc, char **argv)
{
    // argc = 2;
    // argv[1] = "SIGSEGV";

    if (2 != argc)
    {
        printf("input SIGSEGV or SIGBUS or SIGILL or SLEEP");
        return 0;
    }

    // RegSig();
    // int r = sigsetjmp(env,1);
    // if (r == 0)
    // {
    pid_t pid;
    if ((pid = fork()) == 0)
    {
        if (!strcmp("SIGSEGV", argv[1]))
        {
            func1();
        }
        else if (!strcmp("SIGBUS", argv[1]))
        {
            func3();
        }
        else if (!strcmp("SIGILL", argv[1]))
        {
            func5();
        }
        else if (!strcmp("SLEEP", argv[1]))
        {
            sleep(100);
        }
    }

    int i = 0;
    while (i != 2)
    {
        printf("father work\n");
        sleep(2);
        i++;
    }

    waitpid(pid, NULL, WNOHANG);
    // }
    // else
    // {
    //     printf("jump this code !!");
    // }

    return 0;
}
